import { EventToPlayerService } from 'src/modules/event-to-player/event-to-player.service';
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import {
  TeamEventList,
  DoubleEventList,
  SingleEventList,
  EventTypeEnum,
} from 'src/common/constant/enums';
import logger from 'src/common/utils/log';
import { EventService } from 'src/modules/event/event.service';
import { PlayerSignup } from 'src/modules/player-signup/entities/player-signup.entity';
import { EventToPlayer } from '../entities/event-to-player.entity';
import { random } from 'lodash';
import { log } from 'console';
import { MatchService } from 'src/modules/match/match.service';

export type CustomConfirmE2PParam = {
  player1: PlayerSignup;
  player2?: PlayerSignup;
  teamName?: string;
  eventType?: EventTypeEnum;
};

@Injectable()
export class ConfirmPlayerE2PService {
  constructor(
    private readonly eventService: EventService,
    private readonly eventToPlayerService: EventToPlayerService,
    private readonly matchService: MatchService,
  ) {}

  async confirmPlayerE2P(
    eventId: number,
    confirmE2PType: 'random' | 'custom',
    customE2PConfig: {
      [orderNum: number]: number[];
    },
    stageIndex: number = 0,
  ) {
    logger.info(
      `confirmPlayerE2P eventId: ${eventId} confirmE2PType: ${confirmE2PType} customE2PConfig: ${Object.keys(customE2PConfig)}`,
    );
    // 将eventId下边的所有player 落在E2P上
    // confirmE2PType === radom 随机分配,将所商场的player 随机分配到E2P上
    // confirmE2PType === custom 自定义分配,将所商场的player 按照customE2PConfig分配到E2P上，key代表签位，PlayerSignup表示该签位对应的player
    // 业务开始
    const playerIds = Object.values(customE2PConfig).flat();
    const eventWithE2PAndSignup = await this.eventService.findForConfirmE2P(
      eventId,
      playerIds,
    );
    let updateE2PList: EventToPlayer[] = [];
    const {
      eventToPlayers: e2pList,
      playerSignups,
      type: eventType,
    } = eventWithE2PAndSignup;
    const eventToPlayers = e2pList.filter(
      (v) => v.stageOrderInEvent === stageIndex,
    );
    logger.info(
      `findForConfirmE2P res ${eventToPlayers.length} ${playerSignups.length} ${eventType}`,
    );
    if (!playerSignups || !playerSignups.length) {
      throw new HttpException(
        '该赛事没有报名选手',
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    if (!eventToPlayers || !eventToPlayers.length) {
      throw new HttpException(
        '该赛事没有坑位',
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    logger.info(
      `赛事 ${eventId} ${eventType} E2P数量: ${playerSignups.length} playerSignups: ${playerSignups.length}`,
    );
    if (confirmE2PType === 'custom') {
      if (!customE2PConfig) {
        throw new HttpException(
          '制定E2P类型为自定义时，必须传入customE2PConfig',
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }
      logger.info(
        `自定义 抽签customE2PConfig.length ${Object.keys(customE2PConfig).length}`,
      );
      // updateE2PList = this.referPlayerToE2P(
      //   eventToPlayers,
      //   playerSignups,
      //   customE2PConfig,
      // );
      updateE2PList = this.doConfirmE2P(
        playerSignups,
        eventToPlayers,
        eventType,
        customE2PConfig,
      );
    } else if (confirmE2PType === 'random') {
      updateE2PList = this.doConfirmE2P(
        playerSignups,
        eventToPlayers,
        eventType,
      );
    }

    logger.info(
      `更新E2P数量: ${updateE2PList.length} updateE2PList: ${updateE2PList.map((v) => v.id).join(', ')}`,
    );
    await this.validateBeforeSave(updateE2PList);
    return await this.eventToPlayerService.saveList(updateE2PList);
  }

  async validateBeforeSave(e2pList: EventToPlayer[]) {
    // 获取所有轮空的选手
    const byePlayerIds = [];
    e2pList.forEach((v) => {
      if (v.isByePlayer) {
        byePlayerIds.push(v.id);
      }
    });
    if (byePlayerIds.length) {
      const hasByePlayerMatches =
        await this.matchService.listByE2PIds(byePlayerIds);
      // 检查是否存在homePlayer 和 awayPlayer 都是轮空的比赛
      hasByePlayerMatches.forEach((match) => {
        if (
          byePlayerIds.includes(match.homePlayerId) &&
          byePlayerIds.includes(match.awayPlayerId)
        ) {
          throw new HttpException(
            `比赛 ${match.id} 的homePlayer 和 awayPlayer 都是轮空的 homePlayerId: ${match.homePlayerId} awayPlayerId: ${match.awayPlayerId}`,
            HttpStatus.INTERNAL_SERVER_ERROR,
          );
        }
      });
    }
  }

  doConfirmE2P(
    playerSignups: PlayerSignup[],
    eventToPlayers: EventToPlayer[],
    eventType: EventTypeEnum,
    customE2PConfig?: {
      [orderNum: number]: number[];
    },
  ) {
    const referredPlayerOrder = {};
    if (customE2PConfig) {
      Object.entries(customE2PConfig).forEach(([orderNum, playerIds]) => {
        const _orderNum = Number(orderNum);
        if (!playerIds || !playerIds.length) {
          throw new HttpException(
            `orderNum ${_orderNum} 没有对应的playerIds`,
            HttpStatus.INTERNAL_SERVER_ERROR,
          );
        }
        playerIds.forEach((playerId) => {
          if (referredPlayerOrder[playerId]) {
            throw new HttpException(
              `playerId ${playerId} 被分配了两个orderNumber ${_orderNum} ${referredPlayerOrder[playerId]}`,
              HttpStatus.INTERNAL_SERVER_ERROR,
            );
          }
          referredPlayerOrder[playerId] = _orderNum;
        });
      });
    }
    let updateE2PList: EventToPlayer[];
    const mainPlayers: PlayerSignup[] = playerSignups.filter(
      (v) => v.isMainPlayer,
    );
    const regIndexList: string[] = eventToPlayers.map((v) => {
      return v.registrationIndex;
    });
    logger.info(
      `mainPlayers count: ${mainPlayers.length}; regs: ${regIndexList.join(',')}`,
    );
    if (TeamEventList.includes(eventType)) {
      // 团赛
      // 过滤出所有，标记为team的数据
      const teamPlayers: PlayerSignup[] = mainPlayers;
      // 如果多余没有或者不足2人，直接报错
      if (teamPlayers.length < 2) {
        throw new HttpException(
          `报名人数 ${teamPlayers.length} 不足2个`,
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }
      // 给每个组合随机生成一个随机数,范围为E2P的regindex值
      const updateConfig: { [regIndex: string]: CustomConfirmE2PParam } = {};
      const teamPlayerRegIndexList = regIndexList.filter((v) => {
        return !v.includes('-');
      });
      if (teamPlayerRegIndexList.length < teamPlayers.length) {
        throw new HttpException(
          `报名人数 ${teamPlayers.length} 超出报名总人数 ${teamPlayerRegIndexList.length}`,
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }
      teamPlayers.forEach((teamPlayer) => {
        // let teamPlayerRegIndex = null;
        let teamPlayerRegIndex = null;
        const referOrder = referredPlayerOrder[teamPlayer.id];
        if (!isNaN(Number(referOrder))) {
          // 被配置了顺序
          teamPlayerRegIndex = teamPlayerRegIndexList[referOrder];
          if (!teamPlayerRegIndex) {
            throw new HttpException(
              `order ${referOrder} 没有对应的签位(坑位最小值为0)`,
              HttpStatus.INTERNAL_SERVER_ERROR,
            );
          }
          if (updateConfig[teamPlayerRegIndex]) {
            // 一定是产生了逻辑错误
            throw new HttpException(
              `团队 ${teamPlayer.name} 的order ${referOrder} 被其他团队 占用`,
              HttpStatus.INTERNAL_SERVER_ERROR,
            );
          }
        } else {
          while (
            teamPlayerRegIndex === null ||
            updateConfig[teamPlayerRegIndex]
          ) {
            const _idx = random(0, teamPlayerRegIndexList.length - 1);
            if (!Object.keys(referredPlayerOrder).includes(_idx)) {
              // idx 不能占用被配置的顺序
              teamPlayerRegIndex = teamPlayerRegIndexList[_idx];
            }
          }
        }

        updateConfig[teamPlayerRegIndex] = {
          player1: teamPlayer,
          teamName: teamPlayer.organization,
        };
        if (!teamPlayer.subPlayerSignups) {
          throw new HttpException(
            `团队 ${teamPlayer.organization} 没有subPlayerSignups`,
            HttpStatus.INTERNAL_SERVER_ERROR,
          );
        }
        teamPlayer.subPlayerSignups.forEach((subPlayer) => {
          const stageEvent = subPlayer.stageEvent;
          if (!stageEvent) {
            return;
          }
          const { eventOrder, type } = stageEvent;
          if (DoubleEventList.includes(type)) {
            // 双打
            if (!updateConfig[`${teamPlayerRegIndex}-${eventOrder}`]) {
              updateConfig[`${teamPlayerRegIndex}-${eventOrder}`] = {
                player1: subPlayer,
                teamName: teamPlayer.organization,
                eventType: type,
              };
            } else {
              updateConfig[`${teamPlayerRegIndex}-${eventOrder}`].player2 =
                subPlayer;
            }
          } else if (SingleEventList.includes(type)) {
            // 单打
            updateConfig[`${teamPlayerRegIndex}-${eventOrder}`] = {
              player1: subPlayer,
              teamName: teamPlayer.organization,
            };
          }
        });
        Object.entries(updateConfig).forEach(([regIndex, playerInfo]) => {
          const { eventType } = playerInfo;
          if (DoubleEventList.includes(eventType) && !playerInfo.player2) {
            throw new HttpException(
              `双打组合 ${regIndex} 人数不对 已有player ${playerInfo.player1.name}`,
              HttpStatus.INTERNAL_SERVER_ERROR,
            );
          }
        });
      });
      // 遍历teame的subPlayers，并根据stageEnvent.order 进行分组
      // 生成updateConfig
      // 调用referPlayerToE2P
      updateE2PList = this.referPlayerToE2P(
        eventToPlayers,
        playerSignups,
        updateConfig,
      );
    } else if (DoubleEventList.includes(eventType)) {
      // 双打
      // 过滤出所有标记为上场的选手
      // 根据teamName表示两个选手，为一个组合
      const playerTeam: {
        [teamName: string]: [PlayerSignup?, PlayerSignup?];
      } = {};
      if (regIndexList.length < mainPlayers.length / 2) {
        throw new HttpException(
          `报名对数 ${mainPlayers.length / 2} 超出报名总人数 ${regIndexList.length}`,
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }
      // mainPlayers.forEach((playerInfo) => {
      //   const { pairName } = playerInfo;
      //   if (!pairName) {
      //     playerTeam[pairName] = playerTeam[pairName] || [];
      //     playerTeam[pairName].push(playerInfo);
      //   }
      // });
      // let teamCount;
      Object.entries(customE2PConfig).forEach(([orderNum, playerIds]) => {
        const _orderNum = Number(orderNum);
        playerTeam[_orderNum] = playerTeam[_orderNum] || [];
        playerIds.forEach((playerId) => {
          const playerInfo = playerSignups.find((v) => v.id === playerId);
          playerTeam[_orderNum].push(playerInfo);
        });
      });

      // 如果多余没有或者不足2人，直接报错
      const updateConfig: { [regIndex: string]: CustomConfirmE2PParam } = {};
      Object.entries(playerTeam).forEach(([teamName, players], index) => {
        const playerNames = players.map((v) => v.name).join(', ');
        // teamCount = index + 1;
        if (players.length !== 2) {
          throw new HttpException(
            `双打组合 ${teamName} 人数不对 已有player ${playerNames}`,
            HttpStatus.INTERNAL_SERVER_ERROR,
          );
        }
        const referOrder =
          referredPlayerOrder[players[0].id] ||
          referredPlayerOrder[players[1].id];
        let playerRegIndex = null;
        if (!isNaN(Number(referOrder))) {
          // 被配置了顺序
          playerRegIndex = regIndexList[referOrder];
          if (!playerRegIndex) {
            throw new HttpException(
              `order ${referOrder} 没有对应的签位(坑位最小值为0)`,
              HttpStatus.INTERNAL_SERVER_ERROR,
            );
          }
          if (updateConfig[playerRegIndex]) {
            // 一定是产生了逻辑错误
            throw new HttpException(
              `teamName ${teamName} 的order ${referOrder} 被其他player 占用`,
              HttpStatus.INTERNAL_SERVER_ERROR,
            );
          }
        } else {
          while (playerRegIndex === null || updateConfig[playerRegIndex]) {
            const _idx = random(0, regIndexList.length - 1);
            if (!Object.keys(referredPlayerOrder).includes(_idx)) {
              // idx 不能占用被配置的顺序
              playerRegIndex = regIndexList[_idx];
            }
          }
        }

        logger.info(
          `teamName: ${teamName} playerNames: ${playerNames} regIndex: ${playerRegIndex}`,
        );
        // 生成updateConfig
        updateConfig[playerRegIndex] = {
          player1: players[0],
          player2: players[1],
          teamName: teamName,
        };
      });
      // if (teamCount < 2) { // 在自动晋级场景不应该报这个错，而且也不是很必要，因为之前的逻辑并不完善
      //   throw new HttpException(
      //     `双打队数不足: ${teamCount}`,
      //     HttpStatus.INTERNAL_SERVER_ERROR,
      //   );
      // }
      // 给每个组合随机生成一个随机数,范围为E2P的regindex值
      // 生成updateConfig
      // 调用referPlayerToE2P
      updateE2PList = this.referPlayerToE2P(
        eventToPlayers,
        playerSignups,
        updateConfig,
      );
    } else if (SingleEventList.includes(eventType)) {
      //单打
      // // 过滤出所有标记为上场的选手
      // 如果多余没有或者不足2人，直接报错
      if (mainPlayers.length < 2) {
        throw new HttpException(
          `报名人数 ${mainPlayers.length} 不足`,
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }
      if (regIndexList.length < mainPlayers.length) {
        throw new HttpException(
          `报名人数 ${mainPlayers.length} 超出报名总人数 ${regIndexList.length}`,
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }
      // 给每个选手随机生成一个随机数,范围为E2P的regindex值
      const updateConfig: { [regIndex: string]: CustomConfirmE2PParam } = {};
      mainPlayers.forEach((v) => {
        let playerRegIndex = null;
        const referOrder = referredPlayerOrder[v.id];
        if (!isNaN(Number(referOrder))) {
          // 被配置了顺序
          playerRegIndex = regIndexList[referOrder];
          if (!playerRegIndex) {
            throw new HttpException(
              `order ${referOrder} 没有对应的签位(坑位最小值为0)`,
              HttpStatus.INTERNAL_SERVER_ERROR,
            );
          }
          if (updateConfig[playerRegIndex]) {
            // 一定是产生了逻辑错误
            throw new HttpException(
              `playerId ${v.id} 的order ${referOrder} 被其他player 占用`,
              HttpStatus.INTERNAL_SERVER_ERROR,
            );
          }
        } else {
          while (playerRegIndex === null || updateConfig[playerRegIndex]) {
            const _idx = random(0, regIndexList.length - 1);
            if (!Object.keys(referredPlayerOrder).includes(_idx)) {
              // idx 不能占用被配置的顺序
              playerRegIndex = regIndexList[_idx];
            }
          }
        }
        logger.info(`${v.name} regIndex: ${playerRegIndex}`);
        // 生成updateConfig
        updateConfig[playerRegIndex] = {
          player1: v,
        };
      });
      // 调用referPlayerToE2P
      updateE2PList = this.referPlayerToE2P(
        eventToPlayers,
        playerSignups,
        updateConfig,
      );
    }
    return updateE2PList;
  }

  referPlayerToE2P(
    originE2PList: EventToPlayer[],
    originPlayerSignupList: PlayerSignup[],
    updateConfig: {
      [regIndex: string]: CustomConfirmE2PParam;
    },
  ): EventToPlayer[] {
    originE2PList.forEach((v) => {
      v.player = null;
      v.player2 = null;
      // v.team = null;
      v.player1Name = '轮空';
      v.player2Name = null;
      v.teamName = null;
      v.isByePlayer = true;
    });
    const e2pMapByRegIndex = originE2PList.reduce(
      (pre, cur) => {
        pre[cur.registrationIndex] = cur;
        return pre;
      },
      {} as { [regIndex: string]: EventToPlayer },
    );
    const playerSignupMapById = originPlayerSignupList.reduce(
      (pre, cur) => {
        pre[cur.id] = cur;
        return pre;
      },
      {} as { [id: number]: PlayerSignup },
    );
    const validatePlayerSignup = (playerInfo: PlayerSignup) => {
      // if (!playerInfo.id || !playerSignupMapById[playerInfo.id]) {
      if (!playerInfo.id) {
        throw new HttpException(
          `该选手未报名 ${playerInfo.name} ${playerInfo.idCard}`,
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }
      return true;
    };
    Object.entries(updateConfig).forEach(([regIndex, playerInfo]) => {
      if (e2pMapByRegIndex[regIndex]) {
        e2pMapByRegIndex[regIndex].isByePlayer = false;
        if (validatePlayerSignup(playerInfo.player1)) {
          e2pMapByRegIndex[regIndex].player = playerInfo.player1;
          e2pMapByRegIndex[regIndex].player1Name = playerInfo.player1.name;
        }

        if (playerInfo.player2 && validatePlayerSignup(playerInfo.player2)) {
          e2pMapByRegIndex[regIndex].player2 = playerInfo.player2;
          e2pMapByRegIndex[regIndex].player2Name = playerInfo.player2.name;
        }
        if (playerInfo.teamName) {
          e2pMapByRegIndex[regIndex].teamName = playerInfo.teamName;
        }
      } else {
        new HttpException(
          `该签位不存在 ${regIndex}`,
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }
    });
    return originE2PList;
  }
}
